﻿using System;
using System.Web;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using Enterprise.Exceptions;

namespace Enterprise
{
    /// <summary>
    /// DataManager.cs
    /// DataManager read, write and delete XML data from database.
    /// 
    /// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /// Maybe integrate the old xmlmanager to read from app_data. This let's a user deside which one to use. Or?
    /// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class DataManager<T>
    {
        protected T _data;
        private string _RegionID;

        public DataManager()
        {
            _data = (T)Activator.CreateInstance(typeof(T));
        }

        public void LoadData()
        {
            SqlConnection Conn = new SqlConnection(Config.ConnectionString());
            string ID = GetID();
          
            try
            {   //Minimize database calls
                object o= HttpContext.Current.Cache["ModuleData_"+ ID];
                o = null; //dev
                if (o == null)
                {
                    SqlCommand command = new SqlCommand(string.Format("SELECT ObjectData FROM Objects WHERE id={0}", ID), Conn);
                    Conn.Open();
                    SqlDataReader dr = command.ExecuteReader();

                    if (dr.Read())
                    {
                        _data = (T)Enterprise.Utils.SerializeFactory.DeserializeObject((string)dr["ObjectData"], typeof(T));
                        HttpContext.Current.Cache.Insert("ModuleData_" + ID, _data);
                    }
                }
                _data = (T)HttpContext.Current.Cache["ModuleData_" + ID];
            }
            catch (Exception ec) { throw ec; }
            finally { Conn.Close(); }
        }


        /// <summary>
        /// Save Module
        /// </summary>
        public void SaveData(string RegionID)
        {
            this._RegionID = RegionID;

            if (Exist())
                SaveData(SQLCmd.UPDATE);
            else
                SaveData(SQLCmd.INSERT);
        }

        /// <summary>
        /// Save data
        /// </summary>
        public void SaveData()
        {
            if (Exist())
                SaveData(SQLCmd.UPDATE);
            else
                SaveData(SQLCmd.INSERT);
        }



        private void SaveData(SQLCmd cmd)
        {
            string data = Enterprise.Utils.SerializeFactory.SerializeObject(_data);
            string Query = string.Empty;

            switch (cmd)
            {
                case SQLCmd.INSERT:
                    Query = "INSERT INTO Objects VALUES(@ObjectData,@PageID,@RegionID,@SortOrder,@PortalID)";
                    break;
                case SQLCmd.UPDATE:
                    Query = string.Format("UPDATE Objects SET ObjectData=@ObjectData WHERE id={0}", GetID());
                    break;
            }

            if(Query!=string.Empty)
                Execute(Query, data, cmd);
        }


        /// <summary>
        /// Deletes a module from database and remove it from cache
        /// </summary>
        public virtual bool Delete()
        {
            bool success = true;
            SqlConnection Conn = new SqlConnection(Config.ConnectionString());
            try
            {
                Conn.Open();
                SqlCommand cmd = new SqlCommand(string.Format("DELETE FROM Objects WHERE id={0}", GetID()), Conn);
                SqlDataReader dr = cmd.ExecuteReader();

                HttpContext.Current.Cache.Remove("ModuleData_" + GetID());
                HttpContext.Current.Cache.Remove("ID_" + GetID());
            }
            catch { success = false; }
            finally { Conn.Close(); }

            return success;
        }


        /// <summary>
        /// Check if id exist.
        /// </summary>
        /// <returns>True if id exist.</returns>
        protected bool Load()
        {
            object o = HttpContext.Current.Cache["ID_" + GetID()];
            if (o == null)
            {
                SqlConnection Conn = new SqlConnection(Config.ConnectionString());
                try
                {
                    Conn.Open();
                    SqlCommand cmd = new SqlCommand(string.Format("SELECT id FROM Objects WHERE id={0}", GetID()), Conn);
                    SqlDataReader dr = cmd.ExecuteReader();
                    if (dr.Read())
                        HttpContext.Current.Cache.Insert("ID_", GetID());
                }
                catch { return false; }
                finally { Conn.Close(); }
            }
            return (o==null);
        }


        /// <summary>
        /// Does all the work with saving and editing data.
        /// </summary>
        /// <param name="query">The query to execute</param>
        /// <param name="data">The serialized string to insert or update.</param>
        private void Execute(string query, string data, SQLCmd cmd)
        {

            SqlConnection Conn = new SqlConnection(Config.ConnectionString());
            
                SqlCommand command = new SqlCommand();
                Conn.Open();
                command.Connection = Conn;
                command.CommandText = query;

                if(cmd == SQLCmd.UPDATE)
                    command.Parameters.AddWithValue("id", GetID());

                command.Parameters.AddWithValue("ObjectData", data);
                command.Parameters.AddWithValue("PageID", HttpContext.Current.Request["PageID"]);
                
                if(!string.IsNullOrEmpty(_RegionID))
                    command.Parameters.AddWithValue("RegionID", _RegionID);

                if (cmd == SQLCmd.INSERT)
                    command.Parameters.AddWithValue("SortOrder", GetMaxSort());
                
                command.Parameters.AddWithValue("PortalID", 1);

                command.ExecuteNonQuery();
          
        }




        private int GetMaxSort()
        { 
            SqlConnection Conn = new SqlConnection(Config.ConnectionString());
            try
            {
                string sql = string.Format("SELECT MAX(SortOrder)+1 As MX From Objects WHERE RegionID='{0}' AND PageID={1}", _RegionID, HttpContext.Current.Request["PageID"]);
               
                SqlCommand command = new SqlCommand(sql, Conn);
                Conn.Open();
                SqlDataReader dr = command.ExecuteReader();
                if (dr.Read())
                {
                    return Convert.ToInt32(dr["MX"]);
                }
                return 0;

            }catch{return 0;}
        
            finally
            {
                Conn.Close();
            }
        }



        /// <summary>
        /// Check if a current id exists.
        /// </summary>
        /// <returns>If a module's id exists</returns>
        private bool Exist()
        {
            if (GetID() != null)
            {
                SqlConnection Conn = new SqlConnection(Config.ConnectionString());
                SqlCommand command = new SqlCommand(string.Format("SELECT * FROM Objects WHERE id={0}", GetID()), Conn);
                Conn.Open();
                SqlDataReader dr = command.ExecuteReader();
                try
                {
                    if (dr.Read())
                        return true;
                    else
                        return false;
                }
                finally { Conn.Close(); }
            }
            return false;
        }
      
        protected abstract string GetID();
    }
}
